<template>
  <div id="fs-wrapper" class="box">
    <div id="jsmind_container" ref="jsmindContainerRef">
      <span ref="triggerRef" style="position: absolute; top: 0; left: 0; width: 0; height: 0;"></span>
    </div>
    <template v-if="showPopup">
      <el-popover
        ref="popoverRef"
        trigger="click"
        popper-class="jsmind-popover"
        :visible="showPopup"
        :placement="selectedNode.direction == -1 ? 'left' : 'right'"
        :virtual-ref="triggerRef"
        :title="poppoverTitle"
        :width="200"
      >
        <template v-if="props.isEnum">
          <p :title="selectedNode.data.code ? selectedNode.data.code : '无'">枚举值: {{ selectedNode.data.code ? selectedNode.data.code : '无' }}</p>
          <p :title="selectedNode.data.value ? selectedNode.data.value : '无'">枚举名称: {{ selectedNode.data.value ? selectedNode.data.value : '无' }}</p>
          <p :title="selectedNode.data.common ? selectedNode.data.common : '无'">注释: {{ selectedNode.data.common ? selectedNode.data.common : '无' }}</p>
        </template>
        <template v-else>
          <p :title="selectedNode.data.code ? selectedNode.data.code : '无'">参数名: {{ selectedNode.data.code ? selectedNode.data.code : '无' }}</p>
          <p :title="selectedNode.data.name ? selectedNode.data.name : '无'">参数描述: {{ selectedNode.data.name ? selectedNode.data.name : '无' }}</p>
          <p :title="selectedNode.data.recordType === 1 ? '基本类型' : '数组类型'">分类: {{ selectedNode.data.recordType === 1 ? '基本类型' : '数组类型' }}</p>
          <p :title="selectedNode.data.separator ? selectedNode.data.separator : '无'">参数连接符: {{ selectedNode.data.separator ? selectedNode.data.separator : '无' }}</p>
          <p :title="selectedNode.data.typeCode ? selectedNode.data.typeCode : '无'">数据类型: {{ selectedNode.data.typeCode ? selectedNode.data.typeCode : '无' }}</p>
        </template>
      </el-popover>
    </template>

    <div class="mind-footer">
      <div class="mf-toolbar">
        <el-link :underline="false" title="定位" @click="centerMindMap">
          <i class="iconfont icon-jujiao btn"></i>
        </el-link>
        <el-link :underline="false" title="缩小" :disabled="zoomOutDisabled" @click="zoomOut">
          <i class="iconfont icon-suoxiao btn"></i>
        </el-link>
        <el-link :underline="false" title="放大" :disabled="zoomInDisabled" @click="zoomIn">
          <i class="iconfont icon-fangda btn"></i>
        </el-link>
        <el-link :underline="false" title="全屏" @click="toggleFullScreen">
          <i v-if="fsDisabled" class="iconfont icon-fullscreen btn"></i>
          <i v-else class="iconfont icon-exit-fullscreen btn"></i>
        </el-link>
      </div>
      <div v-if="isEdit">
        <el-button @click="handleCreateTask()" type="primary">添加</el-button>
        <el-button @click="removeNode" type="danger" :disabled="disabled">删除</el-button>
      </div>
    </div>
  </div>
</template>
<script setup>
import jsMind from "jsmind";
import { ElMessage, ElMessageBox } from "element-plus";
import { ref, toRaw, defineProps, nextTick, watch, onMounted, computed, onUnmounted } from "vue";
import { cloneDeep } from "lodash";

const props = defineProps({
  isEnum: {
    type: Boolean,
    default: false
  },
  isEdit: {
    type: Boolean,
    default: true
  },
  fatherData: {
    type: Array,
    default: [],
  },
  adminUser: {
    type: String,
    default: "",
  },
  listObj: {
    type: Object,
    default: {},
  },
  handleCreateTask: {
    type: Function,
    default: () => {},
  },
  handleRemoveNode: {
    type: Function,
    default: () => {},
  },
  table_toolbar_clk: {
    type: Function,
    default: () => {},
  },
  handleEdit: {
    type: Function,
    default: () => {},
  },
})
const options = {
  container: "jsmind_container",
  editable: false, // 是否允许拖动和编辑
  mode: "full",
  theme: "primary", // 样式主题
  support_html: true,
  view: {
    draggable: true,
    hmargin: 2000,        // 思维导图距容器外框的最小水平距离
    vmargin: 1000,         // 思维导图距容器外框的最小垂直距离
    line_width: 1, // 思维导图线条的粗细
    line_color: "#409EFF", // 思维导图线条的颜色
    line_style: "curved",
    hide_scrollbars_when_draggable: true, // 隐藏滚动条
    zoom: {
      min: 0.5, // 最小缩放比例
      max: 5.0, // 最大缩放比例
      step: 0.1 // 缩放步长
    },
    custom_node_render: function(jm, element, node) {
      if (!props.isEdit) {
        return false
      }
      if (node.id == "root" || node.id == "add123") {
        return false
      }
      element.innerHTML = `<i class="iconfont icon-bianji"></i> ${node.data.code}`;
      const iconElement = element.querySelector('.icon-bianji');
      iconElement.addEventListener('click', () => {
        windowMindClick(node);
      });
      return true; // 表示已经渲染此节点
    }
  },
  layout: {
    // hspace: 1 // 子节点距离根节点的距离
  }
};
const mindData = {
  meta: {
    name: "",
    author: "user",
    version: "1.0",
  },
  format: "node_tree",
  data: {
    id: "root",
    topic: "111",
    name: "111",
    "background-color": "#409EFF", //主节点默认背景色
  },
};
const jm = ref(null); // jsMind 实例
const showPopup = ref(false); // 弹框显示状态
const selectedNode = ref(null); // 当前选中的节点
const nodeIdToDelete = ref(""); // 要删除的节点ID
const jsmindHeight = ref();
const listObj = ref({})
const jsmindContainerRef = ref()
const triggerRef = ref()
const popoverRef = ref()
const zoomInDisabled = ref(false)
const zoomOutDisabled = ref(false)
const fsDisabled = ref(true)

const poppoverTitle = computed(() => {
  return selectedNode.value.data.code
})

watch(
  [() => props.adminUser, () => props.fatherData, () => props.isEdit],
  ([adminUser, fatherData]) => {
    let dataArr = [];
    dataArr = toRaw(fatherData).map((item, index) => {
      item.topic = item.code;
      item.id = item.id
      const property =
        index % 2 === 0 ? { direction: "left" } : { direction: "right" };
      return { ...item, ...property };
    });
    if (props.isEdit) {
      dataArr.push({
        id: "add123",
        topic: "+",
        direction: "right"
      });
    }
    Object.assign(listObj.value, props.listObj);
    mindData.data.children = dataArr;
    mindData.meta.name = adminUser;
    mindData.data.topic = adminUser;
    if (jm.value === null) {
      nextTick(() => {
        document
      .getElementById("jsmind_container")
      .addEventListener("click", handleNodeClick);
        jm.value = new jsMind(options); // 初始化 jsMind
        jm.value.show(mindData);
        jm.value.view.add_event(jm.value.view, 'mousewheel', () => {
          if (jm.value.view.zoom_current - options.view.zoom.step <= options.view.zoom.min) {
            zoomOutDisabled.value = true
          } else {
            zoomOutDisabled.value = false
          }
          if (jm.value.view.zoom_current + options.view.zoom.step > options.view.zoom.max) {
            zoomInDisabled.value = true
          } else {
            zoomInDisabled.value = false
          }
        })
        jsmindHeight.value = document.querySelector(
        "jmnodes.theme-primary"
      ).style.height;
      })
    } else {
      // 如果已经初始化，直接更新数据
      jm.value.show(mindData);
    }
  },
  {immediate: true, deep: true}
)

const removeNode = () => {
  ElMessageBox.confirm(`正在删除：${selectedNode.value.data.code}，确认删除？`, "提示", {
    confirmButtonText: "确定",
    cancelButtonText: "取消",
    showClose: false,
    center: true
  })
    .then(() => {
      props.handleRemoveNode(selectedNode.value.id)
      showPopup.value = false;
    })
    .catch(() => {
      ElMessage({
        type: 'info',
        message: '取消删除',
      })
    })

};

const disabled = ref(true)

const handleEditNode = (data) => {
  props.handleEdit(data)
}

const getOffsetToParent = (child, parent) => {
  const parentRect = parent.getBoundingClientRect();
  const childRect = child.getBoundingClientRect();

  const offsetX = childRect.left - parentRect.left;
  const offsetY = childRect.top - parentRect.top;

  return { offsetX, offsetY };
}

// 点击节点
const handleNodeClick = (event) => {
  showPopup.value = false;
  disabled.value = true;
  nextTick(() => {
    // 获取点击的节点
    const nodeId = event.target.getAttribute("nodeid");
    nodeIdToDelete.value = nodeId
    if (nodeId) {
      if (nodeId == "add123") {
        props.handleCreateTask()
        showPopup.value = false; // 不显示弹框
      } else {
        disabled.value = false
        mindData.data.children.forEach((child) => {
          jm.value.set_node_color(child.id, "#27365e", null);
        });
        // 设置点击当前节点背景色为#314371
        jm.value.set_node_color(nodeId, "#314371", null);
        const node = jm.value.get_node(nodeId);
        selectedNode.value = node;

        const zoom = jm.value.view.zoom_current;

        const parentDiv = document.querySelector('.jsmind-inner');
        const childDiv = document.querySelector('.theme-primary');

        const offset = getOffsetToParent(childDiv, parentDiv)

        let offsetX = offset.offsetX, offsetY = offset.offsetY;
        offsetY += selectedNode.value._data.view.height * zoom / 2;
        if (selectedNode.value.direction == 1) {
          offsetX += selectedNode.value._data.view.width * zoom + 8 * zoom;
        }

        triggerRef.value.style.top = `${(selectedNode.value._data.view.abs_y) * zoom + offsetY}px`
        triggerRef.value.style.left = `${(selectedNode.value._data.view.abs_x) * zoom + offsetX}px`

        if (selectedNode.value.data.type == 'base') {
          selectedNode.value.data.type = '基本类型'
        }
        showPopup.value = true; // 显示弹框
      }
      if (nodeId == "root") {
        showPopup.value = false; // 不显示弹框
      }
      jm.value.set_node_color('root', '#314371', null)
    } else {
      showPopup.value = false; // 不显示弹框
    }
  })
};
const handleResize = () => {
  jm.value && jm.value.resize()
}
const zoomIn = () => {
  if (jm.value.view.zoom_in()) {
      zoomOutDisabled.value = false;
  } else {
      zoomInDisabled.value = true;
  }
}

const zoomOut = () => {
  if (jm.value.view.zoom_out()) {
    zoomInDisabled.value = false;
  } else {
    zoomOutDisabled.value = true;
  }
}

const toggleFullScreen = () => {
  var elem = document.getElementById('fs-wrapper');
  fsDisabled.value = document.fullscreenElement;
  if (!document.fullscreenElement) {
    if (elem.requestFullscreen) {
      elem.requestFullscreen();
    } else if (elem.mozRequestFullScreen) { /* Firefox */
      elem.mozRequestFullScreen();
    } else if (elem.webkitRequestFullscreen) { /* Chrome, Safari & Opera */
      elem.webkitRequestFullscreen();
    } else if (elem.msRequestFullscreen) { /* IE/Edge */
      elem.msRequestFullscreen();
    }
  } else {
    if (document.exitFullscreen) {
      document.exitFullscreen();
    } else if (document.mozCancelFullScreen) { /* Firefox */
      document.mozCancelFullScreen();
    } else if (document.webkitExitFullscreen) { /* Chrome, Safari and Opera */
      document.webkitExitFullscreen();
    } else if (document.msExitFullscreen) { /* IE/Edge */
      document.msExitFullscreen();
    }
  }

  centerMindMap();
}

const fullscreenchange = () => {
  fsDisabled.value = !document.fullscreenElement;
  centerMindMap();
}

const centerMindMap = () => {
  const jmInstance = jm.value;
  if (!jmInstance) return;

  const view = jmInstance.view;
  const zoom = view.zoom_current;

  // 实际滚动区域大小
  const mindMapWidth = view.size.w * zoom;
  const mindMapHeight = view.size.h * zoom;

  // 窗口大小
  const containerWidth = view.e_panel.clientWidth;
  const containerHeight = view.e_panel.clientHeight;

  const scrollX = (mindMapWidth - containerWidth) / 2;
  const scrollY = (mindMapHeight - containerHeight) / 2;

  view.e_panel.scrollTo(scrollX, scrollY);
}

onMounted(() => {
  window.windowMindClick = (node) => {
    const data = cloneDeep(node.data)
    data.id = node.id
    handleEditNode(data)
  }
  window.addEventListener('resize', handleResize)

  document.addEventListener('fullscreenchange', fullscreenchange);
  document.addEventListener('webkitfullscreenchange', fullscreenchange);
})
onUnmounted(() => {
  window.removeEventListener('resize', handleResize)

  document.removeEventListener('fullscreenchange', fullscreenchange);
  document.removeEventListener('webkitfullscreenchange', fullscreenchange);
})
</script>
<style lang="scss">
#jsmind_container jmnodes.theme-primary .root {
  background: rgb(64, 158, 255) !important;
}

#jsmind_container jmnodes.theme-primary jmnode {
  border-color: #357ebd;
  border-width: 2px;
  border-style: solid;
  background: transparent;
}
#jsmind_container jmnodes.theme-primary jmnode.selected {
  background-color:#314371;
  color:#fff;
}
.iconfont.icon-bianji {
  font-size: 18px;
  cursor: pointer;
  &:hover {
    color: rgb(64, 158, 255);
  }
}

.mind-footer {
  left: 0;
  bottom: 0;
  width: 100%;
  display: flex;
  justify-content: space-between;
  position: absolute;
  z-index: 999;
  background-color: #1F2B4B;
  padding: var(--main-padding);
  height: 64px;
}

.mf-toolbar {
  display: flex;
  align-items: center;
  justify-content: flex-start;
  .el-link + .el-link {
    margin-left: 16px;
  }
}
.mf-toolbar .btn {
  font-size: 22px;
}
</style>
<style lang="scss" scoped>
.btn-box {
  width: 250px;
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 16px;
  position: absolute;
  top: 0;
  z-index: 999;
  span {
    text-align: center;
    height: 32px;
    flex: 1;
    background: #27365E;
    border-radius: 4px 4px 4px 4px;
    border: 1px solid #409EFF;
    cursor: pointer;
    line-height: 32px;
  }
  .active {
    color: #409EFF;
  }
  &.full {
    top: var(--main-padding);
    left: var(--main-padding);
  }
}
.box {
  width: 100%;
  height: 100%;
  min-height: 480px !important;
  position: relative !important;
  background-color: rgb(29, 45, 87);
  overflow-y: hidden !important;
  padding-bottom: 64px;
  display: flex;
  flex-direction: column;
}

#jsmind_container {
  flex: 1;
  border: 1px solid #ddd;
  border-radius: 5px;
  width: 100%;
  border: 1px solid #27365e;
  /* 脑图盒子背景色 */
  background-color: rgb(39, 54, 94);
  font-size: 16px !important;
  overflow: visible;
}

/* 圆点 */
#jsmind_container::before {
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background-image: radial-gradient(circle, #cbced5 1px, transparent 2px);
  background-size: 20px 20px;
  opacity: 0.2;
}

/* 修改确认框内容文字大小 */
.custom-confirm-box .el-message-box__message {
  font-size: 18px;
  /* 设置文字大小 */
  line-height: 1.5;
  /* 调整行高 */
}

.jsmind-popover > p {
  width: 100%;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}
</style>
